home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 04 - 1988 / 04.10 Oct 88 / MSSourcesLong / MS.C < prev    next >
Encoding:
Text File  |  1988-01-18  |  24.2 KB  |  1,099 lines  |  [TEXT/EDIT]

  1. /*________________________________
  2.                     MS.c
  3.  
  4. ________________________________
  5. OPTIONS B=token E=verb G=ASM H=ASM Src J=ASM Symb K=Debug Symb Z=No float
  6.   ________________________________*/
  7. #Options +B +E -G -H -J +K +Z
  8. #asm
  9. .verbose
  10. #endasm
  11. #include "MyTools.p"
  12. #include "MS.h"
  13. /* In order to minimize extern declarations in calling programs
  14.     int has been optioned to int - if you are typing int to shorts you
  15.     are in big trouble! */
  16. //=========================
  17. MSConfig MSInit(confPtr)
  18.     MSConfig        *confPtr;
  19. //=========================
  20. BEGIN_FCT
  21.     static    MSConfig        confPar;
  22.     static    int            confFlg=FALSE;
  23.                 Handle        theHdl;
  24.  
  25. IF (confPtr AND NOT confFlg)
  26. THEN
  27.     SysBeep(30);
  28.     ExitToShell();
  29. ENDIF
  30.  
  31. SWIT ((int)confPtr)
  32.     CASE (NIL)
  33.         IF ((theHdl=GetResource(_MSCFGTYP,0)) EQ NIL)
  34.         THEN
  35.             SysBeep(30);
  36.             SysBeep(30);
  37.             ExitToShell();
  38.         ELSE
  39.             confPar=**((MSConfig **)theHdl);
  40.             confFlg=TRUE;
  41.         ENDIF
  42.     ENDCASE
  43.     CASE (1)
  44.     ENDCASE
  45.     DEFCASE
  46.             confPar=*confPtr;
  47.     ENDCASE
  48. ENDSWIT
  49.  
  50. return (    confPar );
  51.  
  52.  
  53. END_FCT
  54. //=========================
  55. int MSMake(menuID, MIVTFct1,MIVTFct2)
  56.   short                    menuID;
  57.   int                        MIVTFct1;
  58.   int                        MIVTFct2;
  59. //=========================
  60. BEGIN_FCT
  61.  
  62.     MSHdl            theMSH;
  63.     MSPtr            theMSP;
  64.     MenuVerb        theMV, theMF;
  65.     Handle        theHdl;
  66.     long            defVal;
  67.     int            i,j;
  68.     short            dynamCount,staticCount,allocCount;
  69.     MVArgT        defPos;
  70.     MVOpCode        opCode;
  71.     MSConfig        confPar;
  72.     short            progNum=_MSPRG01;
  73.  
  74.  
  75. theMSH=MSGetMSH(menuID,progNum);
  76. HLock(theMSH);
  77. theMSP=*theMSH;
  78. theMF=*theMSP->MVT;
  79. confPar=MSInit(1);
  80.  
  81.     /* Get Menus */
  82. if (NOT (theMSP->MH=GetMenu(menuID)) )
  83.     MSErrExit(progNum,_MSERR02,menuID,0);    
  84.  
  85.     /* Load System resources */
  86. if (BitTst(&theMF, _MFSYSLOD))
  87.     AddResMenu(theMSP->MH,theMSP->sysRes);
  88.  
  89. dynamCount=CountMItems(theMSP->MH);
  90. staticCount=theMSP->staticCount;
  91. allocCount=theMSP->allocCount;
  92.  
  93. /* Trim to allocCount */
  94. IF (BitTst(&theMF, _MFERRTRM))
  95. THEN
  96.     IF (dynamCount GT allocCount)
  97.     THEN
  98.             /* NOT IMPLEMENTED - Put up Alert informing
  99.             User that such and such a menu was trimmed */
  100.     ENDIF
  101. ENDIF
  102. WHILE (dynamCount GT allocCount)
  103.     DelMenuItem(theMSP->MH,dynamCount);
  104.     dynamCount--;
  105. ENDWHILE
  106.  
  107. /* Minimal validation */
  108. if (confPar.dbgFlg)
  109.     MSValidation(theMSH,menuID,staticCount,allocCount);
  110.  
  111.  
  112.     /* If Text toggled, make sure STR# exists */
  113. IF (BitTst(&theMF, _MFHASSTR))
  114. THEN
  115.     if (NOT GetResource(_MSSTRTYP,theMSP->ttgStrID) )
  116.         MSErrExit(progNum,_MSERR07,menuID,0);
  117.  
  118.         /* Set STR# Indx for defaulted TXTTOG types */
  119.     j=NULL;
  120.     FOR (i=1;i LE allocCount;i++)
  121.         opCode=theMSP->MVT[i].opCode;
  122.         IF (opCode EQ _MVTEXTOG OR opCode EQ _MVTTGSET)
  123.         THEN
  124.             if (theMSP->MVT[i].argT[3] LE NULL)
  125.                 theMSP->MVT[i].argT[3]=j*2+1;
  126.             j++;
  127.                     /* Set TXTOG items to TF state    */
  128.             theMV.opCode=theMSP->MVT[i].opCode;
  129.             theMSP->MVT[i].opCode=_MVTEXTOG;
  130.             MSTogBit(menuID,i);
  131.             MSDispatch1(theMSP,menuID,i);
  132.             theMSP->MVT[i].opCode=theMV.opCode;
  133.         ENDIF
  134.     ENDFOR
  135.     
  136. ENDIF
  137.  
  138.     /* Expand  Range for added resources */
  139. IF (BitTst(&theMF, _MFEXPRNG))
  140. THEN    theMV=theMSP->MVT[staticCount];
  141.         if (theMV.opCode NE _MVNZEXRG)
  142.             MSErrExit(progNum,_MSERR09,menuID,staticCount);
  143.         IF (theMV.argT[0] LE NULL)
  144.         THEN    theMV.argT[0]=staticCount;
  145.                 theMV.argT[1]=dynamCount;
  146.                 if (theMV.argT[3])
  147.                     theMV.argT[3]+=staticCount-1;
  148.         ENDIF
  149.         for (i=theMV.argT[0];i LE theMV.argT[1];i++)
  150.             theMSP->MVT[i]=theMV;            
  151. ENDIF
  152.  
  153.     /* Allocate MIVT (Menu Item Values Table*/
  154. if (BitTst(&theMF, _MFALOCTB))
  155.     if (NOT (theMSP->MIVTH=(long **)NewHandle((allocCount+1)*sizeof(long))) )
  156.         MSErrExit(progNum,_MSERR03,menuID,0);
  157.     else
  158.         for (i=NULL;i LE allocCount;i++)
  159.             *((*theMSP->MIVTH)+i)=theMSP->MIVTnullVal;
  160.  
  161.  
  162.     /* MIVT Prep    */
  163. IF (MIVTFct1)
  164. THEN
  165.     theMSP->procID[0]=MIVTFct1;
  166.     BitSet(theMSP->MVT, _MFPRCFLG);
  167. ENDIF
  168. IF (MIVTFct2)
  169. THEN
  170.     theMSP->procID[1]=MIVTFct2;
  171.     BitSet(theMSP->MVT, _MFPRCFLG+1);
  172. ENDIF
  173.  
  174.     /* Build MIVT (Menu Item Values Table*/
  175. if (BitTst(&theMF, _MFBLDTAB))
  176.     if (NOT theMSP->procID[0])
  177.         MSErrExit(progNum,_MSERR10,menuID,0);
  178.     else 
  179.         MSCallProc (theMSP,menuID,0,0);
  180.  
  181.     /* Set Menu and TogFlgs for expanded range */
  182. IF (BitTst(&theMF, _MFSETXRG))
  183. THEN    if (NOT(BitTst(&theMF, _MFEXPRNG)))
  184.                 MSErrExit(progNum,_MSERR06,menuID,0);
  185.         defPos=theMV.argT[3];
  186.         IF (NOT defPos)
  187.         THEN    defVal=theMSP->MIVTdefVal;
  188.                 defPos=staticCount;
  189.                 if (defVal)
  190.                     for (i=defPos;i LE dynamCount;i++)
  191.                         IF (defVal EQ MSGetMIVT(menuID,i))
  192.                         THEN    defPos=i;
  193.                                 break;
  194.                         ENDIF
  195.         ENDIF
  196.     CheckItem(theMSP->MH,defPos,TRUE);
  197.     MSTogBit(menuID,defPos);
  198. ENDIF
  199.  
  200.     /* Set Menu and TogFlgs to PREVious state */
  201. IF (BitTst(&theMF, _MFSETPRE))
  202. THEN    if ( NOT (theHdl=GetResource(_MSPRVTYP,menuID)) )
  203.             MSErrExit(progNum,_MSERR12,menuID,0);
  204.         HLock(theHdl);
  205.         MSAdjTog(menuID,*theHdl,*theHdl+sizeof(ToggleFlag));
  206.         HUnlock(theHdl);
  207. ENDIF
  208.     /* Execute PROC2 if attached    */
  209. MSCallProc (theMSP,menuID,0,1);
  210. HUnlock(theMSH);
  211. return ((int)theMSP->MH);
  212.  
  213. END_FCT
  214. //============================
  215. MSDispatch(menuID, itemNumber)
  216.     short                    menuID;
  217.     short                    itemNumber;
  218. //============================
  219. BEGIN_FCT
  220.     MSHdl                    theMSH;
  221.     MSPtr                    theMSP;
  222.     short                    progNum=_MSPRG02;
  223.     int                    MIVTFct1;
  224.     Handle                theHandle;
  225.  
  226.     if ( NOT (theMSH=(MSHdl)GetResource(_MSMSTTYP,menuID)) )
  227.         return;        /* Don't do anything for non-MST menus */
  228.     HLock(theMSH);
  229.     theMSP=*theMSH;
  230.     MSDispatch1(theMSP,menuID, itemNumber);
  231.     MSCallProc (theMSP,menuID,itemNumber,1);
  232.     HUnlock(theMSH);
  233.  
  234. END_FCT
  235. //============================
  236. MSDispatch1(theMSP,menuID, itemNumber)
  237.     MSPtr            theMSP;
  238.     short            menuID;
  239.     short            itemNumber;
  240. //============================
  241. BEGIN_FCT
  242.     MenuHandle            theMH;
  243.     MenuVerb                theMV;
  244.     MVOpCode                opCode;
  245.     MVArgT                first, last,    parent, other;
  246.     short                    progNum=_MSPRG03;
  247.     Str255                theSTR;
  248.     int                    theTVal, flag,i;
  249.  
  250.     if (itemNumber GT theMSP->allocCount)
  251.         return;
  252.     theMH=theMSP->MH;
  253.     theMV=theMSP->MVT[itemNumber];
  254.     opCode=theMV.opCode;
  255.  
  256.     if (opCode LE _MVNORMAL)
  257.         return;
  258.     if (itemNumber GT theMSP->allocCount)
  259.         MSErrExit(progNum,_MSERR17,menuID,itemNumber);
  260.  
  261.     first=theMV.argT[0];
  262.     last=theMV.argT[1];
  263.     parent=theMV.argT[2];
  264.     other=theMV.argT[3];
  265.  
  266.     theTVal=MSTogBit(menuID,itemNumber);
  267.     MSDispatch2(theMSP,menuID,itemNumber,opCode,&first,&last,&parent,&other)
  268.     SWIT (opCode)
  269.         CASE (_MVCHKTOG)
  270.             CheckItem(theMH,itemNumber,theTVal);
  271.         ENDCASE
  272.         CASE (_MVTEXTOG)
  273.             IF (MSGetIndStr(&theSTR,menuID, other+theTVal) LT NULL)
  274.             THEN    MSErrExit(progNum,_MSERR08,menuID,itemNumber);
  275.             ELSE    SetItem(theMH,itemNumber,&theSTR);
  276.             ENDIF
  277.         ENDCASE
  278.         CASE (_MVENABPR)
  279.             MSTogBit(menuID,other);
  280.             MSEnable(theMH,itemNumber,theTVal);
  281.             MSEnable(theMH,other,NOT theTVal);
  282.         ENDCASE
  283.         CASE (_MVNZEXRG)
  284.             MSClear(theMSP,first,last,opCode);
  285.             CheckItem(theMH,itemNumber,TRUE);
  286.             MSTogBit(menuID, itemNumber);
  287.         ENDCASE
  288.         CASE (_MVCMRGRS)
  289.             SWIT (itemNumber EQ parent)
  290.                 CASE(TRUE)            /* Parent */
  291.                     IF (NOT theTVal)
  292.                     THEN    MSTogBit(menuID,itemNumber);
  293.                     ELSE    MSClear(theMSP,first,last,opCode);
  294.                             CheckItem(theMH,itemNumber,TRUE);
  295.                             IF ((itemNumber GE first) AND (itemNumber LE last))
  296.                             THEN    MSTogBit(menuID,itemNumber);    ENDIF
  297.                     ENDIF
  298.                 ENDCASE
  299.                 CASE (FALSE)            /* Member */
  300.                     CheckItem(theMH,itemNumber,theTVal);
  301.                     IF (theTVal)
  302.                     THEN    flag=BitTst(&theMSP->TF,parent)
  303.                     ELSE    flag = NOT MSBitOr(theMSP,first,last,opCode);
  304.                     ENDIF
  305.                     IF (flag)
  306.                     THEN    CheckItem(theMH,parent,NOT theTVal);
  307.                             MSTogBit(menuID,parent);
  308.                     ENDIF
  309.                 ENDCASE
  310.             ENDSWIT
  311.         ENDCASE
  312.         CASE (_MVENBSET)
  313.             IF (itemNumber NE parent)
  314.             THEN    MSTogBit(menuID,itemNumber);
  315.             ELSE    FOR (i=first;i LE last; i++)
  316.                         IF (theMSP->MVT[i].opCode EQ opCode)
  317.                         THEN
  318.                             MSEnable(theMH,i,theTVal);
  319.                             MSTogBit(menuID,i);
  320.                         ENDIF
  321.                     ENDFOR
  322.                     if ((itemNumber GE first) AND (itemNumber LE last))
  323.                         MSTogBit(menuID,itemNumber);
  324.                     else    
  325.                         MSEnable(theMH,itemNumber, theTVal);                    
  326.                     itemNumber=other;
  327.                     if (MSGetTog(menuID,itemNumber) EQ theTVal)
  328.                             MSDispatch1(theMSP ,menuID,itemNumber)
  329.             ENDIF
  330.         ENDCASE
  331.         CASE (_MVTTGSET)
  332.             IF (itemNumber NE parent)
  333.             THEN    MSTogBit(menuID,itemNumber);
  334.             ELSE    FOR (i=first;i LE last; i++)
  335.                         IF (theMSP->MVT[i].opCode EQ opCode)
  336.                         THEN
  337.                             IF (NIL GT MSGetIndStr(&theSTR,
  338.                                 menuID,theMSP->MVT[i].argT[3]+theTVal))
  339.                             THEN    MSErrExit(progNum,_MSERR08,menuID,i);
  340.                             ELSE    SetItem(theMH,i,&theSTR);
  341.                                     MSTogBit(menuID,i);
  342.                             ENDIF
  343.                         ENDIF
  344.                     ENDFOR
  345.                     IF ((itemNumber GE first) AND (itemNumber LE last))
  346.                     THEN    MSTogBit(menuID,itemNumber);
  347.                     ELSE    IF (NIL GT MSGetIndStr(&theSTR,
  348.                                     menuID,other+theTVal))
  349.                             THEN    MSErrExit(progNum,_MSERR08,menuID,itemNumber);
  350.                             ELSE    SetItem(theMH,itemNumber,&theSTR);
  351.                             ENDIF
  352.                     ENDIF
  353.             ENDIF
  354.         ENDCASE
  355.     ENDSWIT
  356.  
  357. END_FCT
  358. //================================================
  359. MSDispatch2(theMSP,menuID,itemNumber,opCode,first,last,parent,other)
  360.     MSPtr        theMSP;
  361.     short        menuID,itemNumber;
  362.     MVOpCode    opCode;
  363.     MVArgT    *first,*last,*parent,*other;
  364. //================================================
  365. /* default Parser */
  366. BEGIN_FCT
  367.     int        i,j;
  368.     MenuVerb    fakeVerb;
  369.     short        dynamCount;
  370.     short        progNum=_MSPRG11;
  371.  
  372. dynamCount=CountMItems(theMSP->MH);
  373. SWIT (opCode)
  374.     CASE (_MVENABPR)
  375.         if (*other LE NULL)
  376.             *other=itemNumber+(*other?-1:1);
  377.     ENDCASE
  378.     CASE (_MVNZEXRG)
  379.     CASE (_MVCMRGRS)
  380.     CASE (_MVENBSET)
  381.     CASE (_MVTTGSET)
  382.         if (*first AND *last)
  383.             return;
  384.         else
  385.             if (*first OR *last)
  386.                 MSErrExit(progNum,_MSERR14,menuID,itemNumber);
  387.  
  388.         for (i=itemNumber;i GT NULL;i--)
  389.             if (theMSP->MVT[i].opCode EQ _MVMENLIN)
  390.                 break;
  391.         for (j=itemNumber;j LE dynamCount;j++)
  392.             if (theMSP->MVT[j].opCode EQ _MVMENLIN)
  393.                 break;
  394.  
  395.         *first=++i;
  396.         *last=--j;
  397.         if (opCode EQ _MVNZEXRG)
  398.             break;
  399.         IF (*parent LE NULL)
  400.         THEN
  401.             *parent=*first;
  402.         ELSE
  403.             *parent+=*first-1;
  404.             if (*parent LT *first OR *parent GT *last)
  405.                 MSErrExit(progNum,_MSERR16,menuID,itemNumber);
  406.         ENDIF
  407.         if (opCode NE _MVENBSET)
  408.             break;
  409.         if (*other GT NULL)
  410.             break;
  411.         itemNumber=(*other)?*first-2:*last+2;
  412.         if (itemNumber LE NULL OR itemNumber GT dynamCount)
  413.             MSErrExit(progNum,_MSERR15,menuID,itemNumber);
  414.         for (i=NULL;i LT _MVARGDIM;i++)
  415.             fakeVerb.argT[i]=theMSP->MVT[itemNumber].argT[i];
  416.         MSDispatch2(theMSP,menuID,itemNumber,_MVCMRGRS,
  417.                         &fakeVerb.argT[0],&fakeVerb.argT[1],
  418.                         &fakeVerb.argT[2],&fakeVerb.argT[3]);
  419.         *other=fakeVerb.argT[2];
  420.     ENDCASE
  421. ENDSWIT
  422.  
  423. END_FCT
  424. //==============================================
  425. int    MSInsMenuItem(menuID,menuStr,after,theMV)
  426.     short            menuID;
  427.     char            *menuStr;
  428.     short            after;
  429.     MenuVerb        *theMV;
  430. //==============================================
  431. BEGIN_FCT
  432.     short            progNum=_MSPRG12;
  433.     short            staticCount, dynamicCount,allocCount;
  434.     MSHdl            theMSH;
  435.     MSPtr            theMSP;
  436.     long            menLineTxt=0x02282D00;    /* (- pascal string    */
  437.  
  438.     theMSH=MSGetMSH(menuID,progNum);
  439.     HLock(theMSH);
  440.     theMSP=*theMSH;
  441.     MSParseAfter(theMSP,&after,&staticCount,&dynamicCount,&allocCount);
  442.     
  443.     if (dynamicCount GE allocCount)
  444.         return (-_MSERR17); /* dynamicCount GE allocCount */ 
  445.     SWIT (theMV->opCode)
  446.         CASE (_MVTEXTOG)
  447.         CASE (_MVTTGSET)
  448.             return (-_MSERR24);    /* not implemented */
  449.         ENDCASE
  450.     ENDSWIT
  451.     MSShift(theMSP,after,1);
  452.     theMSP->MVT[after+1] = *theMV;
  453.     if (theMV->opCode EQ _MVMENLIN)
  454.         menuStr=(char *)(&menLineTxt);
  455.     InsMenuItem(theMSP->MH,menuStr,after);
  456.  
  457.     HUnlock(theMSH);
  458.     return (after+1);
  459.                 
  460.  
  461. END_FCT
  462. //=========================
  463. MSDelMenuItem(menuID,itemNumber)
  464.     short            menuID;
  465.     short            itemNumber;
  466. //=========================
  467. BEGIN_FCT
  468.     short            progNum=_MSPRG13;
  469.     short            staticCount, dynamicCount,allocCount;
  470.     MSHdl            theMSH;
  471.     MSPtr            theMSP;
  472.  
  473.     theMSH=MSGetMSH(menuID,progNum);
  474.     HLock(theMSH);
  475.     theMSP=*theMSH;
  476.  
  477.     MSParseAfter(theMSP,&itemNumber,&staticCount,&dynamicCount,&allocCount);
  478.     if (itemNumber EQ staticCount)
  479.         if (staticCount EQ dynamicCount)
  480.             return (-_MSERR17);
  481.         else
  482.             itemNumber++;
  483.     MSShift(theMSP,itemNumber,-1);
  484.     DelMenuItem(theMSP->MH,itemNumber);
  485.  
  486.     HUnlock(theMSH);
  487.     return (NULL);
  488.     
  489.  
  490. END_FCT
  491. //=========================================
  492. MSParseAfter(theMSP,after,staticCount,dynamicCount,allocCount)
  493.     MSPtr        theMSP;
  494.     short        *after,*staticCount,*dynamicCount,*allocCount;
  495. //=========================================
  496. BEGIN_FCT
  497.     short            offset=0;
  498.     MSConfig        theConfig;    
  499.  
  500.     *dynamicCount=CountMItems(theMSP->MH);
  501.     *staticCount=theMSP->staticCount;
  502.     *allocCount=theMSP->allocCount;
  503.  
  504.     theConfig=MSInit(1);
  505.     if (theConfig.relFlg)
  506.         offset=*staticCount;
  507.  
  508.     *after+=offset;
  509.     if (*after LE *staticCount)
  510.         *after=*staticCount;
  511.     else
  512.         if (*after GE *dynamicCount)
  513.             *after=*dynamicCount;
  514.  
  515.  
  516. END_FCT
  517. //=========================
  518. MSShift(theMSP,itemNumber,direction)
  519.     MSPtr        theMSP;
  520.     short        itemNumber, direction;
  521. //=========================
  522. BEGIN_FCT
  523.     short            progNum=_MSPRG14;
  524.     MenuVerb        *MVTP;
  525.     long             *MIVTP;
  526.     ToggleFlag    *TFP;
  527.     int            i,k,first,last,dynamicCount;
  528.  
  529. /*
  530.     insert                        delete
  531.     dir=+1 Δ=-1                dir=-1    Δ=+1
  532.                  -----                             -----
  533.     last        √-----    ^        first            ^-----    |
  534.                 √-----    |                        ^-----    √
  535.                 √-----                            ^-----    
  536.     first         -----    i--    last             -----    i++
  537.  
  538.     in all cases T[i]=T[i+Δ]
  539.  
  540. */
  541.  
  542.     MVTP=theMSP->MVT;
  543.     TFP=&theMSP->TF;
  544.     dynamicCount=CountMItems(theMSP->MH);
  545.     if (BitTst(theMSP->MVT, _MFALOCTB))
  546.         MIVTP=(*theMSP->MIVTH);
  547.     else
  548.         MIVTP=NIL;
  549.  
  550.     IF (direction GT NULL)
  551.     THEN /* Insert */
  552.         first=dynamicCount+1;
  553.         last=itemNumber+1;
  554.     ELSE /* Delete */
  555.         first=itemNumber;
  556.         last=dynamicCount;
  557.     ENDIF
  558.     direction*=-1;
  559.  
  560.     FOR (i=first;i-last;i+=direction)
  561.         *(MVTP+i)=*(MVTP+i+direction);
  562.         k=BitTst(TFP,i+direction);
  563.         if (k)
  564.             BitSet(TFP,i);
  565.         else
  566.             BitClr(TFP,i);
  567.         if (MIVTP)
  568.             *(MIVTP+i)=*(MIVTP+i+direction);
  569.     ENDFOR
  570.  
  571.     /* NULL value problems here */
  572.     for (i=0;i LT _MVARGDIM;i++)
  573.         *((char *)(MVTP+last)+i)='\0';
  574.     if (MIVTP)
  575.         *(MIVTP+last)=theMSP->MIVTnullVal;
  576.     BitClr(TFP,last);
  577.  
  578. END_FCT
  579.  
  580. //=====================
  581. MSInsert(menuID, beforeID)
  582.     short        menuID,beforeID;
  583. //=======================
  584. BEGIN_FCT
  585.     MSHdl            theMSH;
  586.     MenuHandle    theMH;
  587.     short            progNum=_MSPRG04;
  588.  
  589.     theMSH=MSGetMSH(menuID,progNum);
  590.     HLock(theMSH);
  591.     theMH=(*theMSH)->MH;
  592.     if (NOT theMH)
  593.         MSErrExit(progNum,_MSERR02,menuID,0);
  594.     if (BitTst((*theMSH)->MVT, _MFSUBMEN))
  595.         InsertMenu(theMH,-1);
  596.     else    if (beforeID NE NULL)
  597.                 InsertMenu(theMH,beforeID);
  598.             else
  599.                 InsertMenu(theMH,(*theMSH)->beforeID);
  600.     
  601.     HUnlock(theMSH);
  602.  
  603. END_FCT
  604. //=================
  605. MSDelete(menuID)
  606.     short        menuID;
  607. //=================
  608. BEGIN_FCT
  609.     DeleteMenu(menuID);
  610. END_FCT
  611. //=====================
  612. MSDispose(menuID)
  613.     short        menuID;
  614. //=======================
  615. BEGIN_FCT
  616.     MSHdl            theMSH;
  617.     MSPtr            theMSP;
  618.     short            progNum=_MSPRG05;
  619.  
  620.     theMSH=MSGetMSH(menuID,progNum);
  621.     HLock(theMSH);
  622.  
  623.     theMSP=*theMSH;
  624.     DisposeMenu(theMSP->MH);
  625.     ReleaseResource(theMSP->MH);
  626.     if (BitTst(theMSP->MVT, _MFALOCTB))
  627.         DisposHandle(theMSP->MIVTH );
  628.     
  629.     HUnlock(theMSH);
  630.     ReleaseResource(theMSH);
  631.  
  632. END_FCT
  633. //=========================
  634. int MSGetTog(menuID,itemNumber)
  635.     short        menuID;
  636.     short        itemNumber;
  637. //=======================
  638. BEGIN_FCT
  639.     MSHdl            theMSH;
  640.     MSPtr            theMSP;
  641.     Handle        theHdl;
  642.     short            progNum=_MSPRG06;
  643.  
  644.     theMSH=MSGetMSH(menuID,progNum);
  645.     return(BitTst(&(*theMSH)->TF,itemNumber));
  646.  
  647. END_FCT
  648. //=========================
  649. int MSGetMIVT(menuID,itemNumber)
  650.     short        menuID, itemNumber;
  651. //=======================
  652. BEGIN_FCT
  653.     MSHdl            theMSH;
  654.     MSPtr            theMSP;
  655.     short            progNum=_MSPRG07;
  656.  
  657.     theMSH=MSGetMSH(menuID,progNum);
  658.     theMSP=*theMSH;
  659.     if (itemNumber GT theMSP->allocCount)
  660.         MSErrExit(progNum,_MSERR17,menuID,itemNumber);
  661.  
  662.     return (*((*theMSP->MIVTH)+itemNumber));
  663.  
  664. END_FCT
  665. //=========================
  666. MSSetMIVT(menuID,itemNumber,value)
  667.     short            menuID, itemNumber;
  668.     long            value;
  669. //=======================
  670. BEGIN_FCT
  671.     MSHdl            theMSH;
  672.     MSPtr            theMSP;
  673.     short            progNum=_MSPRG07;
  674.  
  675.     theMSH=MSGetMSH(menuID,progNum);
  676.     theMSP=*theMSH;
  677.     if (itemNumber GT theMSP->allocCount)
  678.             MSErrExit(progNum,_MSERR17,menuID,itemNumber);
  679.     *((*theMSP->MIVTH)+itemNumber)=value;
  680.  
  681. END_FCT
  682. //=========================
  683. int MSFindMIVT(menuID,first,last,theMIVT)
  684.     short            menuID,first,last;
  685.     long            theMIVT;
  686. //=======================
  687. BEGIN_FCT
  688.     short            progNum=_MSPRG15;
  689.     MSHdl            theMSH;
  690.     long            *theMIVTP;
  691.     int            i,allocCount;
  692.     
  693.  
  694.     theMSH=MSGetMSH(menuID,progNum);
  695.     if (NOT BitTst((*theMSH)->MVT, _MFALOCTB))
  696.         return (-1);
  697.     theMIVTP=(*(*theMSH)->MIVTH);
  698.     allocCount=(*theMSH)->allocCount;
  699.     first=(first LT 1)?1:first;
  700.     last=(last GT allocCount)?allocCount:last;
  701.     for (i=first;i LE last; i++)
  702.         if (*(theMIVTP+i) EQ theMIVT)
  703.             return (i);
  704.     return (NULL)
  705.  
  706. END_FCT
  707. //=========================
  708. MSAdjTog(menuID,theTF,theMSK)
  709.     short                menuID;
  710.     ToggleFlag        *theTF,*theMSK;
  711. //=======================
  712. BEGIN_FCT
  713.     MSHdl            theMSH;
  714.     MSPtr            theMSP;
  715.     short            progNum=_MSPRG08;
  716.     int            i;
  717.     short            allocCount;
  718.  
  719. theMSH=MSGetMSH(menuID,progNum);
  720. HLock(theMSH);
  721. theMSP=*theMSH;
  722. allocCount=(*theMSH)->allocCount;
  723. for (i=1; i LE allocCount;i++)
  724.     if (BitTst(theMSK,i))
  725.         IF (        BitTst(&(*theMSH)->TF,i)
  726.                 NE     BitTst(theTF,i)    )
  727.         THEN
  728.             MSDispatch1(theMSP,menuID,i);
  729.             MSCallProc (theMSP,menuID,i,1);
  730.         ENDIF
  731.  
  732. HUnlock(theMSH);
  733.  
  734. END_FCT
  735. //=========================
  736. MSAdjPREV(menuID)
  737.     short        menuID;
  738. //=======================
  739. BEGIN_FCT
  740.     MSHdl            theMSH;
  741.     Handle        thePREVH;
  742.     Ptr            thePREVP;
  743.     short            progNum=_MSPRG10;
  744.     int            i;
  745.     short            theErr,allocCount;
  746.  
  747. theMSH=MSGetMSH(menuID,progNum);
  748. if ( NOT (thePREVH=GetResource(_MSPRVTYP,menuID))  )
  749.     MSErrExit(progNum,_MSERR12,menuID,0);
  750. allocCount=(*theMSH)->allocCount;
  751. HLock(thePREVH);
  752. thePREVP=*thePREVH;
  753.  
  754. for (i=1; i LE allocCount;i++)
  755.     if (BitTst(thePREVP+sizeof(ToggleFlag),i))
  756.         if (        BitTst(&(*theMSH)->TF,i)
  757.                 NE     BitTst(thePREVP,i)    )
  758.             if (BitTst(&(*theMSH)->TF,i))
  759.                 BitSet(thePREVP,i);
  760.             else
  761.                 BitClr(thePREVP,i);
  762.  
  763. ChangedResData(thePREVH);
  764. if (theErr=ResError())
  765.     MSErrExit(progNum,_MSERR13,menuID,theErr);
  766. WriteResource(thePREVH);
  767. if (theErr=ResError())
  768.     MSErrExit(progNum,_MSERR13,menuID,theErr);
  769. HUnlock(thePREVH);
  770. ReleaseResource(thePREVH);
  771.  
  772. END_FCT
  773. //=========================
  774. MSHdl MSGetMSH(menuID,progNum)
  775.     short        menuID;
  776.     short        progNum;
  777. //=======================
  778. BEGIN_FCT
  779.         MSHdl            theMSH;
  780.     if ( NOT (theMSH=(MSHdl)GetResource(_MSMSTTYP,menuID)) )
  781.         MSErrExit(progNum,_MSERR01,menuID,0);
  782.     return (theMSH );
  783.  
  784.  
  785. END_FCT
  786. //=================
  787. int MSTogBit(menuID,itemNumber)
  788.     short        menuID;
  789.     short        itemNumber;
  790. //================
  791.         /*_______  toggles and returns current value   ________*/
  792. BEGIN_FCT
  793.     MSHdl            theMSH;
  794.     MSPtr            theMSP;
  795.     short            progNum=_MSPRG09;
  796.  
  797.     theMSH=MSGetMSH(menuID,progNum);
  798.     theMSP=*theMSH;
  799.     if (itemNumber GT theMSP->allocCount)
  800.         MSErrExit(progNum,_MSERR17,menuID,itemNumber);
  801.  
  802.     IF (BitTst(&theMSP->TF,itemNumber))
  803.     THEN    BitClr(&theMSP->TF,itemNumber);
  804.             return(FALSE);
  805.     ELSE    BitSet(&theMSP->TF,itemNumber);
  806.             return(TRUE);
  807.     ENDIF
  808.  
  809. END_FCT
  810. //=================
  811. int MSGetIndStr(theStrP,menuID,strIndx)
  812.     char            *theStrP;
  813.     short            menuID,strIndx;
  814. //=================
  815. BEGIN_FCT
  816.     MSHdl        theMSH;
  817.     short        progNum=_MSPRG19;
  818.  
  819.  
  820.     theMSH=MSGetMSH(menuID,progNum);
  821.     menuID=(*theMSH)->ttgStrID;
  822.     return (fGetIndStr(theStrP,menuID,strIndx));
  823.  
  824. END_FCT
  825. //=================
  826. int fGetIndStr(theStrP,strID,strIndx)
  827.     char            *theStrP;
  828.     short            strID,strIndx;
  829. //=================
  830. /* Like NOT IN ROM GetIndStr, except returns length,
  831.     or -1 if Indx out of bounds */
  832. BEGIN_FCT
  833.     Handle        theSTRH;
  834.     short            i,j;
  835.     short            maxIndx;
  836.     long            len;
  837.     char            *s;
  838.  
  839.     if ( NOT (theSTRH=GetResource(_MSSTRTYP,strID)) )
  840.         return (-1);
  841.     maxIndx=*((short *)(*theSTRH));
  842.     if ((strIndx GT maxIndx) OR (strIndx LE NULL))
  843.         return (-1);
  844.  
  845.     s=*theSTRH + sizeof(short);
  846.     for (i=1; i LT strIndx; i++)
  847.         s+=(unsigned char)(*s)+1;
  848.     
  849.     len=(unsigned char)(*s)+1;
  850.     *theStrP=NULL;
  851.     BlockMove(s,theStrP,len);
  852.     return(len);
  853.  
  854. END_FCT
  855.  
  856. //=========================
  857. MSErrExit(progName,errNum,menuID,itemNum)
  858.     short    progName,errNum,menuID,itemNum;
  859. //=======================
  860. BEGIN_FCT
  861.     Handle    theHdl;
  862.     Str255    paramTxt[4],sjunk;
  863.     int        i;
  864.     short        separator=0x012F; /* "/" with length byte */
  865.     short        len;
  866.     char        *s;
  867.     MSConfig    confg;
  868.  
  869.     confg=MSInit(1);
  870.     for (i=NULL;i LT 4;i++) 
  871.         paramTxt[i].count=NULL;
  872.     IF ((theHdl=GetResource('ALRT',confg.alrtID)) EQ NULL
  873.             OR GetResource('DITL',confg.alrtID) EQ NULL)
  874.     THEN
  875.         SysBeep(30);
  876.         SysBeep(30);
  877.         SysBeep(30);
  878.         ExitToShell();    
  879.     ENDIF
  880.  
  881. IF  (confg.dbgFlg)
  882. THEN
  883.     fGetIndStr(¶mTxt[0],confg.errStrID,_MSERR23);
  884.     theHdl=GetResource('DITL',confg.alrtID);
  885.     s=*theHdl+2;
  886.     s+=13;
  887.     len=*s;
  888.     s+=len+1;
  889.     s+=13;
  890.     len=*s;
  891.     for (i=1; i LE len;i++)
  892.         *(s+i)=paramTxt[0].s[i-1];
  893.  
  894.     MSErrExit1(¶mTxt[0],progName,confg.prgStrID,confg.altPrgStrID);
  895.     MSErrExit1(¶mTxt[1],errNum,confg.errStrID,confg.altErrStrID);
  896.  
  897.     NumToString(menuID,¶mTxt[2]);
  898.     MSPcat(¶mTxt[2],&separator);
  899.     NumToString(itemNum,¶mTxt[3]);
  900.     MSPcat(¶mTxt[2],¶mTxt[3]);
  901.     paramTxt[3].count=NULL;
  902. ENDIF
  903.  
  904. ParamText(¶mTxt[0],¶mTxt[1],¶mTxt[2],¶mTxt[3]);
  905. IF (StopAlert(confg.alrtID,NIL) EQ oK)
  906. THEN
  907.     ExitToShell();
  908. ELSE
  909.     IF    (NOT confg.dbgFlg)
  910.     THEN
  911.             #asm
  912.                 RESET
  913.             #endasm
  914.     ELSE
  915.             return;
  916.     ENDIF
  917. ENDIF
  918.  
  919.  
  920. END_FCT
  921. //=======================================
  922. MSErrExit1(paramStr,strNum,strID,altStrID)
  923.     Str255        *paramStr;
  924.     short            strNum,strID,altStrID;
  925. //=======================================
  926. BEGIN_FCT
  927.     Handle    theHdl;
  928.  
  929.  
  930. if ( (theHdl=GetResource(_MSSTRTYP,strID)) NE NULL )
  931.     if (fGetIndStr(paramStr,strID,strNum) GE NULL)
  932.         return;
  933.  
  934. if (altStrID GE NULL)
  935.     if ( (theHdl=GetResource(_MSSTRTYP,altStrID)) NE NULL )
  936.         if (fGetIndStr(paramStr,altStrID,-strNum) GE NULL)
  937.             return;
  938.  
  939. NumToString(strNum,paramStr);
  940.  
  941.  
  942. END_FCT
  943. /*________________________        STATIC FCTS    _______________________________*/
  944. //==================================================
  945. MSValidation (theMSH, menuID,staticCount,allocCount)
  946.     MSHdl        theMSH;
  947.     short        menuID,staticCount,allocCount;
  948. //==================================================
  949. BEGIN_FCT
  950.     MSPtr        theMSP;
  951.     int        i,byteOffSet,HandleSize;
  952.     short        progNum=_MSPRG20;
  953.  
  954. theMSP=*theMSH;
  955.  
  956. if (staticCount GT allocCount)
  957.     MSErrExit(progNum,_MSERR18,menuID,0);
  958. byteOffSet=_MSFIXLEN+(allocCount+1)*sizeof(MenuVerb);
  959. HandleSize=GetHandleSize(theMSH);
  960. IF (BitTst(theMSP->MVT,_MFPRCPAR))
  961. THEN
  962.     i=*((short *)((char *)theMSP+byteOffSet));
  963.     byteOffSet+=(i+1)*sizeof(short);
  964. ENDIF
  965. if (byteOffSet NE HandleSize)
  966.         MSErrExit(progNum,_MSERR22,menuID,0);
  967.  
  968.     
  969. FOR (i=1;i LE allocCount;i++)
  970.     SWIT (theMSP->MVT[i].opCode)
  971.         CASE (_MVNORMAL)
  972.         CASE (_MVMENLIN)
  973.             if (BitTst(&theMSP->TF,i))
  974.                 MSErrExit(progNum,_MSERR19,menuID,i);
  975.         ENDCASE
  976.         CASE (_MVCHKTOG)
  977.         CASE (_MVTEXTOG)
  978.         CASE (_MVENABPR)
  979.         CASE (_MVNZEXRG)
  980.         CASE (_MVCMRGRS)
  981.         CASE (_MVENBSET)
  982.         CASE (_MVTTGSET)
  983.         ENDCASE
  984.         DEFCASE
  985.             MSErrExit(progNum,_MSERR20,menuID,i);
  986.         ENDCASE
  987.     ENDSWIT
  988. ENDFOR
  989. FOR (i=staticCount+1;i LE _TFBITSZE;i++)
  990.     if (BitTst(&theMSP->TF,i))
  991.                 MSErrExit(progNum,_MSERR21,menuID,i);
  992. ENDFOR
  993.  
  994.  
  995. END_FCT
  996.  
  997. //============================
  998. static MSEnable(theMH,itemNumber,flag)
  999.     MenuHandle            theMH;
  1000.     short                    itemNumber;
  1001.     short                    flag;
  1002. //============================
  1003. BEGIN_FCT
  1004.         IF (flag)
  1005.         THEN    EnableItem(theMH,itemNumber);
  1006.         ELSE    DisableItem(theMH,itemNumber);
  1007.         ENDIF
  1008.  
  1009. END_FCT
  1010. //=================
  1011. static MSClear(theMSP,first, last,opCode)
  1012.     MenuStuff    *theMSP;
  1013.     short            first,last;
  1014.     MVOpCode        opCode;
  1015. //=================
  1016.     /*  Clears all bits in range
  1017.          Unchecks any Checked menu items in range */
  1018. BEGIN_FCT
  1019.     short         i,theMark;
  1020.  
  1021.     FOR(i=first;i LE last;i++)
  1022.         IF (theMSP->MVT[i].opCode EQ opCode)
  1023.         THEN
  1024.             BitClr(&theMSP->TF,i);
  1025.             GetItemMark(theMSP->MH,i,&theMark);
  1026.             if (theMark NE noMark)
  1027.                 CheckItem(theMSP->MH,i,FALSE);
  1028.         ENDIF
  1029.     ENDFOR
  1030.  
  1031.  
  1032. END_FCT
  1033. //=================
  1034. static int MSBitOr(theMSP,first, last,opCode)
  1035.     MSPtr            theMSP;
  1036.     short            first,last;
  1037.     MVOpCode        opCode;
  1038. //=================
  1039.     /*_______ returns    (i..j) togbit k   ________*/
  1040. BEGIN_FCT
  1041. short        i;
  1042.  
  1043.     for (i=first;i LE last;i++)
  1044.         if (theMSP->MVT[i].opCode EQ opCode)
  1045.             if (BitTst(&theMSP->TF,i))
  1046.                 return(TRUE);
  1047.  
  1048.     return(FALSE);
  1049.  
  1050.  
  1051. END_FCT
  1052. //===========
  1053. MSPcat(s1,s2)
  1054. char *s1,*s2;
  1055. //===========
  1056. BEGIN_FCT
  1057.     int i;
  1058.  
  1059.     BlockMove(s2+1,s1+*s1+1,*s2);
  1060.     *s1+=*s2;
  1061.  
  1062. END_FCT
  1063. //====================================
  1064. static MSCallProc (theMSP,menuID,itemNumber,indx)
  1065.     MSPtr        theMSP;
  1066.     short        menuID,itemNumber,indx;
  1067. //====================================
  1068. BEGIN_FCT
  1069. int        MIVTFct;
  1070. Handle    theHdl;
  1071. int        retVal;
  1072. Str255    theStr;
  1073. MSConfig    confg;
  1074. short        progNum=_MSPRG16;
  1075.  
  1076.     if (NOT theMSP->procID[indx])
  1077.         return;
  1078.  
  1079.     MIVTFct=theMSP->procID[indx];
  1080.     IF (NOT BitTst(theMSP->MVT, _MFPRCFLG+indx))
  1081.     THEN    IF (NOT (theHdl=GetResource(_MSPRCTYP,MIVTFct)) )
  1082.             THEN    MSErrExit(progNum,_MSERR04,menuID,indx+1);
  1083.             ELSE    HLock(theHdl);
  1084.                     MIVTFct=(int)(*theHdl);
  1085.             ENDIF
  1086.     ENDIF
  1087.     retVal=(*((int (*)())(MIVTFct)))(theMSP ,menuID,itemNumber,indx);
  1088.     IF (retVal NE _MSMIVTOK)
  1089.     THEN    confg=MSInit(1);
  1090.             if (confg.dbgFlg OR retVal LE _MSMIVTER)
  1091.                 MSErrExit(progNum,_MSERR05,menuID,(-retVal*256)+indx);
  1092.     ENDIF
  1093.     if (NOT BitTst(theMSP->MVT, _MFPRCFLG+indx))
  1094.         HUnlock(theHdl);
  1095.  
  1096. END_FCT
  1097.  
  1098.  
  1099.